package com.sugon.modules.device.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.sugon.dao.DevAmPlanDao;
import com.sugon.dao.DevAmPlanItemDao;
import com.sugon.dao.DevAmPlanPreviewDao;
import com.sugon.dao.DevPlanRuleAmDao;
import com.sugon.entity.*;
import com.sugon.modules.base.consts.SysApproveStatusConst;
import com.sugon.modules.base.model.dto.HandleApproveResult;
import com.sugon.modules.base.model.vo.ProcessProgressConst;
import com.sugon.modules.base.service.impl.AbstractErmsBaseApproveManager;
import com.sugon.modules.device.consts.DevMaintenancePlanFreType;
import com.sugon.modules.device.consts.enums.DevMaintenanceFreRateEnum;
import com.sugon.modules.device.model.DevMaintenPlanItemVO;
import com.sugon.modules.device.model.dto.HalfYearRangeItemDTO;
import com.sugon.modules.device.model.dto.MonthRangeItemDTO;
import com.sugon.modules.device.model.dto.QuarterRangeItemDTO;
import com.sugon.modules.device.model.dto.WeekRangeItemDTO;
import com.sugon.modules.device.model.vo.DevMaintenancePlanItemDateAdjustParamVO;
import com.sugon.modules.device.model.vo.DevMaintenancePlanItemDetailVO;
import com.sugon.modules.device.model.vo.DevMaintenancePlanItemImplementDetailDTO;
import com.sugon.modules.device.service.IDeviceAmPlanManager;
import com.sugon.modules.sys.consts.ProcessProgressStatus;
import com.sugon.service.*;
import com.sugon.utils.ShiroUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author ： YuXD
 * @description：
 * @date ： 2020-11-01 10:59
 * @version: 1.0
 */
@Service
public class DeviceAmPlanManagerImpl extends AbstractErmsBaseApproveManager implements IDeviceAmPlanManager {

    @Autowired
    private DevAmPlanService devAmPlanService;
    @Autowired
    private DevAmPlanItemService devAmPlanItemService;
    @Autowired
    private DevAmPlanPreviewDao devAmPreviewDao;
    @Resource
    private DevAmPlanPreviewService devAmPlanPreviewService;
    @Resource
    private DevPlanRuleAmService devPlanRuleAmService;
    @Resource
    private DevAmRulesService devAmRulesService;
    @Resource
    private DevAmRulesOptionService devAmRulesOptionService;
    @Resource
    private DevAmPlanItemDao devAmPlanItemDao;
    @Resource
    private DevAmPlanDao devAmPlanDao;
    @Autowired
    private DevPlanRuleAmDao devPlanRuleAmDao;
    @Resource
    private DevAmPlanPreviewDao devAmPlanPreviewDao;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteRule(String planId, List<String> ruleIds) {
        for (String devPmRuleId : ruleIds) {
            // 获取设备维护规程
            DevAmRulesEntity devAmRule = devAmRulesService.queryObject(devPmRuleId);
            if (devAmRule == null) {
                continue;
            }
            // 获取设备维护项
            List<DevAmRulesOptionEntity> amRuleItemList = devAmRulesOptionService.getByPlanId(devPmRuleId);
            if (CollectionUtil.isEmpty(amRuleItemList)) {
                continue;
            }
            List<String> mainBaseIdList = amRuleItemList.stream().map(DevAmRulesOptionEntity::getMainBaseId).collect(Collectors.toList());

            // 1、删除维护计划和维护规程的关联
            devPlanRuleAmDao.deletePlanRule(planId, devPmRuleId);
            // 2、删除维护计划项
            devAmPlanItemDao.deletePlanItem(planId, devAmRule.getDevId(), mainBaseIdList);
            // 3、删除下周开始需要生成工单的预览项：后续工单不再生成
            devAmPlanPreviewDao.deleteByPlanId(planId, devAmRule.getDevId(), mainBaseIdList, DateUtil.thisWeekOfYear());
        }
    }

    @Override
    public Map<String, Object> generatePlanImplementFollowTemplateData(String planId) {
        // 声明返回结果
        Map<String, Object> devMaintenancePlanPreviewTemplateData = new HashMap<>(2);
        // 声明维护项列表
        List<Map<String, Object>> planItemList = new ArrayList<>();

        DevAmPlanEntity devAmPlan = devAmPlanService.queryObject(planId);
        org.apache.shiro.util.Assert.notNull(devAmPlan, "设备维护计划不存在！");

        Integer yearly = devAmPlan.getYearly();

        // 声明周日期列表
        Date begionOfYear = com.sugon.modules.utils.DateUtil.initDate(devAmPlan.getYearly(), 1, 1);
        List<WeekRangeItemDTO> weeksList = com.sugon.modules.utils.DateUtil.listWeeksOfYear(null, begionOfYear, begionOfYear, com.sugon.modules.utils.DateUtil.initDate(yearly, 12, 31));
        List<DevMaintenancePlanItemDetailVO> planItemDetailList = devAmPlanDao.getByPlanId(planId);
        if (CollectionUtil.isNotEmpty(planItemDetailList)) {
            for (DevMaintenancePlanItemDetailVO planItemDetail : planItemDetailList) {
                // 获取当初设定的执行日期
                Date date = com.sugon.modules.utils.DateUtil.initDate(yearly, planItemDetail.getMonthNum(), planItemDetail.getDayNum());
                Map<String, Object> planItemDetailMap = BeanUtil.beanToMap(planItemDetail);
                // 设置预计维护实施时间段标点
                recursiveSetExePoint(date, null, planItemDetail.getFreRate(), planItemDetailMap, true, false);

                // 获取当前维护项已完成的周次
                Set<Integer> implementWeeksOfYearList = new HashSet<>();
                List<DevMaintenancePlanItemImplementDetailDTO> implementDetailList = planItemDetail.getImplementDetailList();
                if (CollectionUtil.isNotEmpty(implementDetailList)) {
                    for (DevMaintenancePlanItemImplementDetailDTO implementDetail : implementDetailList) {
                        if (implementDetail.getStatus() == 1 && implementDetail.getImplementDate() != null) {
                            implementWeeksOfYearList.add(cn.hutool.core.date.DateUtil.weekOfYear(implementDetail.getImplementDate()));
                        }
                    }
                }
                for (int i = 1; i <= 53; i++) {
                    String key = "value" + i;
                    if (implementWeeksOfYearList.contains(i)) {
                        int[] code = {0x221A};
                        String implementStatus = new String(code, 0, 1);
                        Object value = planItemDetailMap.putIfAbsent(key, implementStatus);
                        if (value != null) {
                            planItemDetailMap.put(key, value + " " + implementStatus);
                        }
                    } else {
                        planItemDetailMap.putIfAbsent("value" + i, "");
                    }
                }
                planItemList.add(planItemDetailMap);
            }
        }
        devMaintenancePlanPreviewTemplateData.put("planItemList", planItemList);
        devMaintenancePlanPreviewTemplateData.put("weeksList", weeksList);
        return devMaintenancePlanPreviewTemplateData;
    }

    @Override
    public Map<String, Object> generateDevMaintenancePlanPreviewTemplateData(String yearly, String planIdlist) {
        if (StrUtil.isNotEmpty(yearly)) {
            // 清空指定年度设备维护计划预览项
            //devMaintenancePlanPreviewService.delete(yearly);
        }
        // 声明返回结果
        Map<String, Object> devAmPlanPreviewTemplateData = new HashMap<>(2);
        // 声明周日期列表
        Date begionOfYear = com.sugon.modules.utils.DateUtil.initDate(NumberUtil.parseInt(yearly), 1, 1);
        List<WeekRangeItemDTO> weeksList = com.sugon.modules.utils.DateUtil.listWeeksOfYear(null, begionOfYear, begionOfYear, com.sugon.modules.utils.DateUtil.initDate(NumberUtil.parseInt(yearly), 12, 31));
        // 声明维护项列表
        final List<Map<String, Object>> planItemList = CollectionUtil.newArrayList();
        // 获取yearly年份下所有的设备维护计划
        Map<String, Object> param = new HashMap<>();
        param.put("yearly", yearly);
        if (StrUtil.isNotEmpty(planIdlist)) {
            param.put("planIdlist", planIdlist);
        }
        List<DevAmPlanEntity> devMaintenancePlanList = devAmPlanService.queryList(param);
        if (CollectionUtil.isNotEmpty(devMaintenancePlanList)) {
             /*
                1、获取所有计划维护项
                2、遍历维护项，根据每一项设置的日期和时间间隔，找到并设置
                没有的项不进行任何设置
             */
            List<String> planIdList = devMaintenancePlanList.stream().map(DevAmPlanEntity::getId).collect(Collectors.toList());
            List<DevMaintenancePlanItemDetailVO> planItemDetailList = devAmPreviewDao.getByPlanIds(planIdList);
            if (CollectionUtil.isNotEmpty(planItemDetailList)) {
                int[] code = {0x25CF};
                // 一个设备一个维护项为一行
                Map<String, List<DevMaintenancePlanItemDetailVO>> temMap = planItemDetailList.stream().collect(Collectors.groupingBy(item -> item.getDevId() + item.getMainBaseId()));
                temMap.forEach((uniqueCode, itemList) -> {
                    Map<String, Object> planItemDetailMap = BeanUtil.beanToMap(itemList.get(0));
                    List<Integer> weeklyList = itemList.stream().map(item -> item.getWeeksOfYear()).collect(Collectors.toList());
                    for (Integer weekOfYear : weeklyList) {
                        // 判断下是否实施过，如果实施过
                        planItemDetailMap.put("value" + weekOfYear, new String(code, 0, 1));
                    }
                    for (int i = 1; i <= 53; i++) {
                        String value = "";
                        if (weeklyList.contains(i)) {
                            value = new String(code, 0, 1);
                        }
                        planItemDetailMap.putIfAbsent("value" + i, value);
                    }
                    planItemList.add(planItemDetailMap);
                });

                // 统计工时
                Map<Integer, List<DevMaintenancePlanItemDetailVO>> groupedMap = planItemDetailList.stream().collect(Collectors.groupingBy(DevMaintenancePlanItemDetailVO::getWeeksOfYear));
                for (WeekRangeItemDTO weekRangeItem : weeksList) {
                    List<DevMaintenancePlanItemDetailVO> temItems = groupedMap.get(weekRangeItem.getWeeklyOfYear());
                    if (CollectionUtil.isEmpty(temItems)) {
                        continue;
                    }
                    weekRangeItem.addManHours(temItems.stream().mapToLong(item -> item.getCheckDatePrud() + item.getCheckDateUprud()).sum());
                }
            }
        }
        // 一个设备放到一起
        List<Map<String, Object>> planItemList2 = planItemList.stream().sorted(Comparator.comparing(o -> MapUtil.getStr(o, "devCode"))).collect(Collectors.toList());
        devAmPlanPreviewTemplateData.put("planItemList", planItemList2);
        devAmPlanPreviewTemplateData.put("weeksList", weeksList);
        return devAmPlanPreviewTemplateData;
    }


    /**
     * 处理车间审核
     *
     * @param approveItemId 审批事项ID
     * @param approveStatus 审批状态
     * @param remark        审批备注
     * @return
     */
    @Override
    public HandleApproveResult handleWorkshopApprove(String approveItemId, Integer approveStatus, String remark) {
        HandleApproveResult handleApproveResult = new HandleApproveResult();
        DevAmPlanEntity devMaintenancePlan = devAmPlanService.queryObject(approveItemId);
        Assert.notNull(devMaintenancePlan, "维护计划信息不存在，请确认！");
        // 校验规程进度
        Assert.isTrue(ProcessProgressConst.DEPT_APPROVING.equals(devMaintenancePlan.getStatus()), "只可以审核处于审核中的维护计划！");
        // 设置审核信息
        devMaintenancePlan.setApproveDate(DateUtil.date());
        devMaintenancePlan.setApprover(ShiroUtils.getUserId());
        devMaintenancePlan.setApproveRemark(remark);
        // 如果审核通过
        if (approveStatus == SysApproveStatusConst.PASSED) {
            devMaintenancePlan.setStatus(ProcessProgressConst.PASSED);
            int rows = devAmPlanService.update(devMaintenancePlan);
            if (rows > 0) {
                handleApproveResult.setProcessProgressStatus(ProcessProgressStatus.END);
                handleApproveResult.setTitle(devMaintenancePlan.getPlanName());
                handleApproveResult.setNextNodeLevel(0);
            }
        } else if (approveStatus == SysApproveStatusConst.NOT_PASSED) {
            devMaintenancePlan.setStatus(ProcessProgressConst.NOT_PASSED);
            int rows = devAmPlanService.update(devMaintenancePlan);
            if (rows > 0) {
                handleApproveResult.setProcessProgressStatus(ProcessProgressStatus.ING);
                handleApproveResult.setTitle(devMaintenancePlan.getPlanName());
                handleApproveResult.setUserId(devMaintenancePlan.getModifyUser());
            }
        }
        return handleApproveResult;
    }

    @Override
    public void disablePlanItemByDevId(String devId, String remark) {
        // 获取指定设备本年度的计划明细项
        List<DevAmPlanItemEntity> maintenanceTicketItems = devAmPlanItemService.getCurrentYearlyPlanItemListByDevId(devId);
        if (CollectionUtil.isNotEmpty(maintenanceTicketItems)) {
            maintenanceTicketItems.forEach(maintenanceTicketItem -> {
                maintenanceTicketItem.setIsEnabled(0);
                maintenanceTicketItem.setGmtModified(DateUtil.date());
                maintenanceTicketItem.setRemark(remark);
                devAmPlanItemService.update(maintenanceTicketItem);
            });
        }
    }

    @Override
    public boolean autoAdjust(String planId) {
        /*
            找出所有的设备维护计划项
            找出需要排除的周次

         */
        DevAmPlanEntity plan = devAmPlanService.queryObject(planId);
        cn.hutool.core.lang.Assert.notNull(plan);
        List<DevMaintenPlanItemVO> planItemList = devAmPlanItemService.queryByPlanId(planId, null);
        cn.hutool.core.lang.Assert.isTrue(CollectionUtil.isNotEmpty(planItemList));
        // 按照每个维护项的总工时量，降序显示
        planItemList = planItemList.stream().sorted(Comparator.comparing(DevMaintenPlanItemVO::getWorkHours).reversed()).collect(Collectors.toList());

        // 获取不生成设备维护工单的周次：
        Set<Integer> loadExcludeWeeklySet = loadExcludeWeeklySet(plan.getExcludeRange());

        // 声明本年度周次列表
        Date beginOfYear = plan.getStartDate();
        int currentYear = DateUtil.year(beginOfYear);
        Date endOfYear = plan.getEndDate();
        List<WeekRangeItemDTO> weeklyList = com.sugon.modules.utils.DateUtil.listWeeksOfYear(null, beginOfYear, beginOfYear, endOfYear);
        // 过滤掉：第一周是否满七天 + 设定不生成维护工单的周次
        weeklyList = weeklyList.stream().filter(weekly -> weekly.getDays() == 7 && !loadExcludeWeeklySet.contains(weekly.getWeeklyOfYear())).collect(Collectors.toList());

        // 获取当前维护计划如果执行一年的话的总工时，最终用作后续平均用
        int totalWeekly = weeklyList.size();
        Long totalHours = computeTotalHours(totalWeekly, planItemList);

        // 计算每周的平均工作量
        long weeklyAvgHours = totalHours / totalWeekly;
        // 已分配工时
        long handledWeeklyAvgHours = 0L, currentWeeklyAvgHours = 0L;

        /*
            1、先给每个周次平均分配工作量
            2、找出需要屏蔽的周，把对应的工作量分配或者省略掉
                周次维护项 -> 删除
                月次维护项 -> 分配给当前
         */
        // 获取已维护频率为key的分组
        Map<Integer, List<DevMaintenPlanItemVO>> freRateMap = planItemList.stream().sorted(Comparator.comparing(DevMaintenPlanItemVO::getFreRate)).collect(Collectors.groupingBy(DevMaintenPlanItemVO::getFreRate));

        // 获取维护频率数组
        DevMaintenanceFreRateEnum[] freRateArray = DevMaintenanceFreRateEnum.values();
        for (DevMaintenanceFreRateEnum freRate : freRateArray) {
            List<DevMaintenPlanItemVO> maintenanceItems = freRateMap.get(freRate.getValue());
            if (CollectionUtil.isEmpty(maintenanceItems)) {
                continue;
            }
            // 同一个设备放到一起
            Map<String, List<DevMaintenPlanItemVO>> maintenanceItemMap = maintenanceItems.stream().collect(Collectors.groupingBy(DevMaintenPlanItemVO::getDevId));

            if (freRate.getValue() == DevMaintenanceFreRateEnum.WEEKLY.getValue()) {
                for (WeekRangeItemDTO weeklyItem : weeklyList) {
                    maintenanceItemMap.forEach((devId, maintenItems) -> {
                        weeklyItem.addDevPlanItemMap(devId, maintenItems);
                    });
                }
            } else if (freRate.getValue() == DevMaintenanceFreRateEnum.FORTNIGHT.getValue()) {
                // 每两周一次的维护项不多，先全部添加
                for (int i = 1; i < totalWeekly; i += 2) {
                    Set<Map.Entry<String, List<DevMaintenPlanItemVO>>> entries = maintenanceItemMap.entrySet();
                    for (Map.Entry<String, List<DevMaintenPlanItemVO>> entry : entries) {
                        weeklyList.get(i).addDevPlanItemMap(entry.getKey(), entry.getValue());
                    }
                }
            } else if (freRate.getValue() == DevMaintenanceFreRateEnum.MONTH.getValue()) {
                List<MonthRangeItemDTO> monthlyList = com.sugon.modules.utils.DateUtil.change2Month(weeklyList);
                for (MonthRangeItemDTO monthly : monthlyList) {
                    // 填充设备维护项列表
                    fillWeeklyDevMaintenanceItem(monthly.getWeeklyList(), maintenanceItemMap, weeklyAvgHours, currentWeeklyAvgHours);
                }
            } else if (freRate.getValue() == DevMaintenanceFreRateEnum.QUARTER.getValue()) {
                // 季度
                List<QuarterRangeItemDTO> quarterList = com.sugon.modules.utils.DateUtil.change2Quarter(weeklyList);
                for (QuarterRangeItemDTO quarter : quarterList) {
                    // 填充设备维护项列表
                    fillWeeklyDevMaintenanceItem(quarter.getWeeklyList(), maintenanceItemMap, weeklyAvgHours, currentWeeklyAvgHours);
                }
            } else if (freRate.getValue() == DevMaintenanceFreRateEnum.HALF_YEAR.getValue()) {
                // 半年
                List<HalfYearRangeItemDTO> halfYearList = com.sugon.modules.utils.DateUtil.change2HalfYear(weeklyList);
                for (HalfYearRangeItemDTO halfYear : halfYearList) {
                    // 填充设备维护项列表
                    fillWeeklyDevMaintenanceItem(halfYear.getWeeklyList(), maintenanceItemMap, weeklyAvgHours, currentWeeklyAvgHours);
                }
            } else if (freRate.getValue() == DevMaintenanceFreRateEnum.YEAR.getValue()) {
                // 年度
                fillWeeklyDevMaintenanceItem(weeklyList, maintenanceItemMap, weeklyAvgHours, currentWeeklyAvgHours);
            }
            // 累加已处理工时
            handledWeeklyAvgHours += maintenanceItems.stream().mapToLong(item -> item.getCheckDatePrud() + item.getCheckDateUprud()).sum();
        }
        // 删除现有计划的预览数据
        devAmPreviewDao.deleteByPlanId(planId, null, null, null);
        for (WeekRangeItemDTO weekly : weeklyList) {
            Map<String, List<DevMaintenPlanItemVO>> planItemMap = weekly.getPlanItemMap();
            planItemMap.forEach((devId, tmp) -> {
                for (DevMaintenPlanItemVO planItem : tmp) {
                    devAmPlanPreviewService.recordDeviceMaintenancePlanExeItem(planId, null, devId, planItem.getMainBaseId(), currentYear, weekly.getWeeklyOfYear());
                }
            });
        }
        return true;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean correlateMaintenancePlanAndRule(String planId, String[] ruleIds) {
        /*
        1、建立设备维护计划与设备维护规程之间的关联关系
        2、建立设备维护计划与设备维护库中的维护项之间的关联关系
         */
        for (String ruleId : ruleIds) {
            DevAmRulesEntity devAmRules = devAmRulesService.queryObject(ruleId);
            if (devAmRules == null) {
                continue;
            }
            // 1、建立维护计划和维护规程之间的关联关系
            if (!devPlanRuleAmService.checkIsExists(planId, ruleId)) {
                devPlanRuleAmService.save(new DevPlanRuleAmEntity(planId, ruleId));
            }
            // 2、建立维护计划和维护计划项之间的关联关系
            // 获取规程下的维护明细列表
            List<DevAmRulesOptionEntity> devPlanOptionList = devAmRulesOptionService.getByPlanId(ruleId);
            if (CollectionUtil.isEmpty(devPlanOptionList)) {
                continue;
            }
            DevAmPlanItemEntity devPlanMainItem;
            for (DevAmRulesOptionEntity devPlanOptionEntity : devPlanOptionList) {
                String mainBaseId = devPlanOptionEntity.getMainBaseId();
                String devId = devAmRules.getDevId();
                if (!devAmPlanItemService.isExists(planId, devId, mainBaseId)) {
                    devPlanMainItem = new DevAmPlanItemEntity(planId, mainBaseId);
                    devPlanMainItem.setDevId(devId);
                    devAmPlanItemService.save(devPlanMainItem);
                }
            }
        }
        return true;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean adjustDevMaintenancePlanItem(List<DevMaintenancePlanItemDateAdjustParamVO> devMaintenancePlanItemParams) {
        if (CollectionUtil.isEmpty(devMaintenancePlanItemParams)) {
            return true;
        }
        List<DevAmPlanItemEntity> planItemList = CollectionUtil.newArrayList();
        Set<String> pmPlanIdSet = CollectionUtil.newHashSet();
        for (DevMaintenancePlanItemDateAdjustParamVO devMaintenancePlanItemParam : devMaintenancePlanItemParams) {
            String[] devMaintenancePlanItemIdArray = devMaintenancePlanItemParam.getDevMaintenancePlanItemIds().split(",");
            if (ArrayUtil.isEmpty(devMaintenancePlanItemIdArray)) {
                continue;
            }
            for (String planItemId : devMaintenancePlanItemIdArray) {
                DevAmPlanItemEntity planItem = devAmPlanItemDao.queryObject(planItemId);
                cn.hutool.core.lang.Assert.notNull(planItem);
                pmPlanIdSet.add(planItem.getPlanId());
                // 周计划调整时不包含月份字符串
                if (devMaintenancePlanItemParam.getMonthNum() != null) {
                    planItem.setMonthNum(devMaintenancePlanItemParam.getMonthNum());
                }
                planItem.setDayNum(devMaintenancePlanItemParam.getDayNum());
                int updateFlag = devAmPlanItemService.update(planItem);
                cn.hutool.core.lang.Assert.isTrue(updateFlag > 0, "更新设备维护项失败！");
                planItemList.add(planItem);
            }
        }
        // 重新生成调整想的预览数据
        if (CollectionUtil.isNotEmpty(planItemList)) {
            devAmPlanPreviewService.rebuild(planItemList);
        }
        // 移除每个维护计划中排除的周次
        for (String pmPlanId : pmPlanIdSet) {
            DevAmPlanEntity amPlan = devAmPlanService.queryObject(pmPlanId);
            cn.hutool.core.lang.Assert.isTrue(amPlan != null);
            // 获取需要排除的周次Set
            Set<Integer> excludeWeeklySet = amPlan.loadExcludeWeeklySet();
            if (CollectionUtil.isEmpty(excludeWeeklySet)) {
                continue;
            }
            // 删除非工作周的预览数据
            devAmPreviewDao.conditionDelete(pmPlanId, amPlan.getYearly(), excludeWeeklySet);
        }
        return true;
    }

    @Override
    public void changeAmRule(String originRuleId, String targetRuleId) {
        // 先校验原规程是否已参与指定设备维护计划，如果没有，则终止后续逻辑
        List<DevPlanRuleAmEntity> existList = devPlanRuleAmService.list(null, originRuleId);
        if (CollectionUtil.isEmpty(existList)) {
            return;
        }

        /*
            找出原规程参与指定的设备维护计划
            对其中的设备
            维护计划-维护规程关联
            维护计划项
            排班计划进行替换
         */
        // 获取原设备维护规程信息
        DevAmRulesEntity originAmRule = devAmRulesService.queryObject(originRuleId);
        cn.hutool.core.lang.Assert.notNull(originAmRule);
        // 获取新设备维护规程信息
        DevAmRulesEntity targetAmRule = devAmRulesService.queryObject(targetRuleId);
        cn.hutool.core.lang.Assert.notNull(targetAmRule);
        // 获取目标维护规程项下所有的设备维护项
        List<DevAmRulesOptionEntity> targetAmRuleItemList = devAmRulesOptionService.getByPlanId(targetRuleId);
        if (CollectionUtil.isEmpty(targetAmRuleItemList)) {
            return;
        }
        // 获取设备维护项ID列表
        List<String> devPmItemIdList = targetAmRuleItemList.stream().map(DevAmRulesOptionEntity::getMainBaseId).collect(Collectors.toList());

        // 更新设备维护计划-维护规程关联
        Date current = DateUtil.date();
        for (DevPlanRuleAmEntity devPlanRule : existList) {
            devPlanRule.setRuleId(targetRuleId);
            int updateNum = devPlanRuleAmService.update(devPlanRule);
            if (updateNum > 0) {
                  /*
                    更新维护计划
                    找出差异化，并且进行删除
                 */
                // 找出该计划下当前设备的维护项
                List<DevMaintenPlanItemVO> originPmItems = devAmPlanItemService.queryByPlanId(devPlanRule.getPlanId(), targetAmRule.getDevId());
                if (CollectionUtil.isEmpty(originPmItems)) {
                    continue;
                }
                // 删除原规程有的，现规程没有的
                for (DevMaintenPlanItemVO originPmItem : originPmItems) {
                    if (!devPmItemIdList.contains(originPmItem.getMainBaseId())) {
                        // 删除维护计划项
                        devAmPlanItemService.delete(originPmItem.getId());
                        // 删除排班计划项：
                        devAmPlanPreviewDao.deleteByPlanId(devPlanRule.getPlanId(), targetAmRule.getDevId(), CollectionUtil.newArrayList(originPmItem.getMainBaseId()), DateUtil.thisWeekOfYear());
                    }
                }
                List<String> originPmItemIdList = originPmItems.stream().map(DevMaintenPlanItemVO::getMainBaseId).collect(Collectors.toList());
                // 增加原规程没有的，现规程有的
                List<String> newlyAddPmItemIdList = devPmItemIdList.stream().filter(pmItemId -> !originPmItemIdList.contains(pmItemId)).collect(Collectors.toList());
                if (CollectionUtil.isNotEmpty(newlyAddPmItemIdList)) {
                    List<DevAmPlanItemEntity> rebuildList = CollectionUtil.newArrayList();
                    for (String newlyAddPmItemId : newlyAddPmItemIdList) {
                        // 保存设备维护计划项信息
                        DevAmPlanItemEntity pmPlanItem = new DevAmPlanItemEntity();
                        pmPlanItem.setPlanId(devPlanRule.getPlanId());
                        pmPlanItem.setMainBaseId(newlyAddPmItemId);
                        pmPlanItem.setMonthNum(1);
                        pmPlanItem.setDayNum(1);
                        pmPlanItem.setDevId(targetAmRule.getDevId());
                        devAmPlanItemService.save(pmPlanItem);
                        rebuildList.add(pmPlanItem);
                    }
                    // 自动排班
                    devAmPlanPreviewService.rebuild(rebuildList);
                }
            }
        }
    }

    /**
     * 填充周次的设备维护项
     *
     * @param weeklyList            周次列表
     * @param devMaintenanceItemMap 设备维护项MAP
     * @param weeklyAvgHours        每周的平均工时
     * @param currentWeeklyAvgHours 当前周的平均工时
     */
    private void fillWeeklyDevMaintenanceItem(List<WeekRangeItemDTO> weeklyList, Map<String, List<DevMaintenPlanItemVO>> devMaintenanceItemMap, Long weeklyAvgHours, Long currentWeeklyAvgHours) {
        /*
            分两步
            1、从每个周中尝试找出是否存在某个设备
            2、如果找到后判断这个周工作量是否可以
            注意：一个设备在一个weekList中只允许存在一次
         */

        Set<String> handledDevList = CollectionUtil.newHashSet();

        // 遍历每一周，优先根据既存的设备找
        Iterator<Map.Entry<String, List<DevMaintenPlanItemVO>>> iterator = devMaintenanceItemMap.entrySet().iterator();
        outer:
        for (WeekRangeItemDTO weekly : weeklyList) {
            Map<String, List<DevMaintenPlanItemVO>> existedDevMaintenanceItemMap = weekly.getPlanItemMap();
            if (MapUtil.isNotEmpty(existedDevMaintenanceItemMap)) {
                while (iterator.hasNext()) {
                    Map.Entry<String, List<DevMaintenPlanItemVO>> next = iterator.next();
                    String devId = next.getKey();
                    if (handledDevList.contains(devId)) {
                        continue;
                    }
                    // 尝试判断是否已有
                    List<DevMaintenPlanItemVO> existedMaintenanceItemList = existedDevMaintenanceItemMap.get(devId);
                    if (CollectionUtil.isNotEmpty(existedMaintenanceItemList)) {
                        if (weekly.getOriginManHoursTotal() < weeklyAvgHours && weekly.getOriginManHoursTotal() <= currentWeeklyAvgHours) {
                            // 添加到周次中
                            weekly.addDevPlanItemMap(devId, next.getValue());

                            handledDevList.add(devId);
                        }
                        // 添加成功后移除
                        //iterator.remove();
                        //if (weekly.getOriginManHoursTotal() < weeklyAvgHours && weekly.getOriginManHoursTotal() <= currentWeeklyAvgHours) {
                        //    weekly.addDevPlanItemMap(devId, devMaintenanceItemMap.get(devId));
                        //    // 实时更新周平均工时
                        //    currentWeeklyAvgHours += devMaintenanceItemMap.get(devId).stream().mapToLong(item -> item.getCheckDatePrud() + item.getCheckDateUprud()).sum()/weeklyList.size();
                        //    handledDevIdSet.add(devId);
                        //}
                    }
                }

            }
        }
        // 剩下的只要工时未满，就可以放入
        if (MapUtil.isNotEmpty(devMaintenanceItemMap)) {
            outer:
            for (WeekRangeItemDTO weekly : weeklyList) {
                iterator = devMaintenanceItemMap.entrySet().iterator();
                while (iterator.hasNext()) {
                    Map.Entry<String, List<DevMaintenPlanItemVO>> entry = iterator.next();
                    String devId = entry.getKey();
                    // 如果已处理，则不进行处理
                    if (handledDevList.contains(devId)) {
                        continue;
                    }
                    if (weekly.getOriginManHoursTotal() <= weeklyAvgHours || weekly.getOriginManHoursTotal() <= currentWeeklyAvgHours) {
                        weekly.addDevPlanItemMap(devId, entry.getValue());
                        handledDevList.add(devId);
                        // 移除
                        //iterator.remove();
                    } else {
                        System.out.println("----------------------" + devId);
                        continue outer;
                    }
                }
            }
        }
        devMaintenanceItemMap.forEach((key, value) -> {
            if (!handledDevList.contains(key)) {
                System.out.println("剩余未处理项：" + key + " : " + value);
            }
        });
    }

    /**
     * 获取日期范围所在的周次，保证不重复
     * 比如2022-01-01,2022-01-03 -> [1,2]
     *
     * @param excludeRange
     * @return
     */
    private Set<Integer> loadExcludeWeeklySet(String excludeRange) {
        Set<Integer> excludeWeeklySet = CollectionUtil.newHashSet();
        if (StrUtil.isNotEmpty(excludeRange)) {
            String[] excludeDayArray = excludeRange.split(",");
            for (String excludeDay : excludeDayArray) {
                excludeWeeklySet.add(DateUtil.parseDate(excludeDay).getField(DateField.WEEK_OF_YEAR));
            }
        }
        return excludeWeeklySet;
    }

    /**
     * 计算当前设备维护计划的总工时(分钟)
     *
     * @param totalWeekly  总周次
     * @param planItemList 维护计划明细
     * @return
     */
    private Long computeTotalHours(int totalWeekly, List<DevMaintenPlanItemVO> planItemList) {
        long totalHours = 0L;
        for (DevMaintenPlanItemVO item : planItemList) {
            Integer freRate = item.getFreRate();
            if (freRate == DevMaintenancePlanFreType.WEEKLY) {
                // 每周
                totalHours += totalWeekly * (item.getCheckDateUprud() + item.getCheckDatePrud());
            } else if (freRate == DevMaintenancePlanFreType.FORTNIGHT) {
                // 每半个月
                totalHours += 24 * (item.getCheckDateUprud() + item.getCheckDatePrud());
            } else if (freRate == DevMaintenancePlanFreType.MONTH) {
                // 每月
                totalHours += 12 * (item.getCheckDateUprud() + item.getCheckDatePrud());
            } else if (freRate == DevMaintenancePlanFreType.QUARTER) {
                // 每个季度
                totalHours += 4 * (item.getCheckDateUprud() + item.getCheckDatePrud());
            } else if (freRate == DevMaintenancePlanFreType.HALF_YEAR) {
                // 每半年
                totalHours += 2 * (item.getCheckDateUprud() + item.getCheckDatePrud());
            } else if (freRate == DevMaintenancePlanFreType.YEAR) {
                // 每年
                totalHours += item.getCheckDateUprud() + item.getCheckDatePrud();
            }
        }
        return totalHours;
    }

    /**
     * 递归循环设置计划实施点
     *
     * @param date              当前日期
     * @param freRate           递归频率
     * @param planItemDetailMap 维护计划内容
     * @param isFirst           是否是第一次
     * @param isRecord          是否记录DEV_MAINTENANCE_PLAN_PREVIEW
     */
    private void recursiveSetExePoint(Date date, Date lastDayCurrentYear, Integer freRate, Map<String, Object> planItemDetailMap, boolean isFirst, boolean isRecord) {
        if (!isFirst) {
            // 根据设备维护计划实施频率对date进行偏移
            switch (freRate) {
                case DevMaintenancePlanFreType.WEEKLY:
                    // 每周执行一次
                    date = cn.hutool.core.date.DateUtil.offsetWeek(date, 1);
                    break;
                case DevMaintenancePlanFreType.FORTNIGHT:
                    // 每半个月执行一次
                    date = cn.hutool.core.date.DateUtil.offsetWeek(date, 2);
                    break;
                case DevMaintenancePlanFreType.MONTH:
                    // 每月执行一次
                    date = cn.hutool.core.date.DateUtil.offsetMonth(date, 1);
                    break;
                case DevMaintenancePlanFreType.QUARTER:
                    // 每季度执行一次
                    date = cn.hutool.core.date.DateUtil.offsetMonth(date, 3);
                    break;
                case DevMaintenancePlanFreType.HALF_YEAR:
                    // 每半年执行一次
                    date = cn.hutool.core.date.DateUtil.offsetMonth(date, 6);
                    break;
                case DevMaintenancePlanFreType.YEAR:
                    // 每年执行一次
                    date = cn.hutool.core.date.DateUtil.offsetMonth(date, 12);
                    break;
            }
        } else {
            lastDayCurrentYear = cn.hutool.core.date.DateUtil.endOfYear(date);
        }
        // 如果计划不再实施起止时间段内，那么不做任何处理
        if (date.compareTo(MapUtil.getDate(planItemDetailMap, "endDate")) > 0 || date.compareTo(lastDayCurrentYear) > 0) {
            return;
        }
        if (com.sugon.modules.utils.DateUtil.between(date, MapUtil.getDate(planItemDetailMap, "startDate"), MapUtil.getDate(planItemDetailMap, "endDate"))) {
            int weekOfYear = cn.hutool.core.date.DateUtil.weekOfYear(date);
            // 如果不是第一次且weekOfYear为1,那么计算当前日期的前一周的周次+1，修复无法显示最后一周BUG
            if (!isFirst && weekOfYear == 1) {
                weekOfYear = cn.hutool.core.date.DateUtil.weekOfYear(cn.hutool.core.date.DateUtil.offsetWeek(date, -1)) + 1;

            }
            int[] code = {0x25CF};
            // 判断下是否实施过，如果实施过
            planItemDetailMap.put("value" + weekOfYear, new String(code, 0, 1));
            if (isRecord) {
                // 生成设备预览记录，便于生成工单
                devAmPlanPreviewService.recordDeviceMaintenancePlanExeItem(MapUtil.getStr(planItemDetailMap, "planId"), MapUtil.getStr(planItemDetailMap, "id"), MapUtil.getStr(planItemDetailMap, "devId"), MapUtil.getStr(planItemDetailMap, "mainBaseId"), cn.hutool.core.date.DateUtil.year(date), weekOfYear);
            }
        }
        recursiveSetExePoint(date, lastDayCurrentYear, freRate, planItemDetailMap, false, isRecord);
    }

}
